package ipc;

import java.io.IOException;
import java.io.File;
import java.io.BufferedInputStream;
import java.io.FileInputStream;

public class SPUDD extends Thread{
	Process ps;
	String spudd_file;
	boolean clear = true;
	private myDD[]  _DD = null;
	private double approx_error;
	boolean running = false;	
	boolean fixed = false;
	boolean finished = false;
	private long[] lastUpdated = null;
	private double[] range = null;
	int horizon;
  	int lastseen = 1;	

	public SPUDD(String spudd_file, double approx_error, int horizon){
		this.spudd_file = spudd_file;
		ps = null;
		this.setPriority(Thread.MAX_PRIORITY-1);
		this.approx_error = approx_error;
		this.horizon = horizon;
		_DD = new myDD[horizon];
		lastUpdated = new long[horizon];
		range = new double[horizon];
	}
	
	public void kill(){
		
		
		while(!clear){
			
		}
		
		System.out.println("Self Killing "+ spudd_file);
		
				
		if( ps != null)
			ps.destroy();

		ps = null;
		this.interrupt();

		this.running = false;
		clear = true;
	}
	
	@Override
	public void run(){
		running = true;
		try{
			System.err.println("Starting SPUDD " + spudd_file);
			ps = Runtime.getRuntime().exec("./Spudd " + spudd_file + " -o "+ spudd_file+" -dd -a allpair -m error -e "+approx_error);
			
			try{
				int x = ps.waitFor();

				if( x != 0 ){
					System.err.println("SPUDD retval not zero "+ x);
					try{
					BufferedInputStream bis = new BufferedInputStream(ps.getErrorStream());
					 
					while( ( x =  bis.read() ) != -1 ){
						System.err.print((char)x);
					}
					}catch(Exception e){
						e.printStackTrace();
					}
				}

				finished = true;

				Main.spuddLog.log("SPUDD finished " + spudd_file);
				System.out.println("SPUDD finished " + spudd_file);
				running = false;
				clear = true;

			} catch (InterruptedException e) {
				Main.exceptionLog.log(e.fillInStackTrace().toString());
				finished = true;
				running = false;
			}
		}catch(IOException e){
			e.printStackTrace();
		}
		this.kill();	
	}

	public myDD getDD(boolean value, int hor) {
		if( !value ){
			try {
				throw new RuntimeException("not supported in this version");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return _DD[lastseen-1 < hor? lastseen-1 : hor];
	}
	
	public boolean isFinished(int hor){
//		System.out.println("wants " + hor +  " " + ( lastseen > hor ) );
		return lastseen > hor && _DD[hor] != null;
	}
	
	public int getLastSeen(){
		return lastseen;
	}

	public double getRange(int hor){
		return range[lastseen-1 < hor? lastseen-1 : hor];
	}

	public void updateDD(long timeout) {
		if( fixed ) 
				return;
		int oldlastseen = lastseen;
	

		for( int i = oldlastseen ; i <= horizon; ++i ){
//			System.err.println(i);
			File f = new File(spudd_file+"-temp.dot-"+i);
			
			if(f.exists()){
				if( f.length() == 0 ){
//					System.err.println("file size 0");
				}
				if( f.lastModified() > lastUpdated[i-1] ){
				File f2 = new File(spudd_file+"-APPvalue.dot-"+i);	
					if( !f2.exists() || f2.lastModified() < f.lastModified() ){						
						boolean ret = f.renameTo(f2);
						if( !ret ){
						    Main.exceptionLog.log("Failed to move "+ f.toString()+" "+ f2.toString());
						    System.err.println("Failed move "+ f.toString()+" "+ f2.toString());
						}
					}
				}
				lastseen=i;
			}else{
				if( i != oldlastseen )
					break;
			}
		}

//		System.err.println("Updating DD "+ oldlastseen+" "+lastseen);

		int i;
		for( i = oldlastseen ; i <= lastseen && i <= horizon && timeout > 0; ++i ){
			long tim = System.currentTimeMillis();
//			System.err.println(i);
			File f = new File(spudd_file+"-APPvalue.dot-"+i);

			if( f.lastModified() <= lastUpdated[i-1] )
				continue;

			try {
				_DD[i-1] = new dot2dd(f.getName()).getDD();
				lastUpdated[i-1] = f.lastModified();
			} catch (Exception e) {
				e.printStackTrace();
			}
			timeout -= (System.currentTimeMillis()-tim);
		}
		if( i < lastseen ) lastseen = i;
//		System.err.println("Updated DD up till "+lastseen);


		if( !running ){
			fixed = true;
		}

		this.updateRange();
	}

	public void updateRange() {
		if( fixed )
			return;

		for( int i = 1; i <= horizon; ++i ){
			try{
				File f = new File(spudd_file+"-C-"+i);
			
				if( f.exists() ){
					FileInputStream fis = new FileInputStream(f);
					BufferedInputStream bis = new BufferedInputStream(fis);
					int rd;
					StringBuffer sb = new StringBuffer();
					while( (rd = bis.read() ) != -1 ){
						sb.append((char)rd);
					}			
					double d = Double.parseDouble(sb.toString());
					range[i-1] = d;
//					System.err.println("C updated from Cfile "+ d);
					bis.close();
					fis.close();
				}
				else{
					try{
						range[i-1] = _DD[i-1].getRange();
					}catch(Exception e){}
				}
			}catch( Exception e ){
				try{
					range[i-1] = _DD[i-1].getRange();
				}catch(Exception e2){}
			}
		}
	}
		
  	public void done(){
		_DD = null;
		range = null;
		lastUpdated = null;
	}		

}
